<?php
/*
* Kusht Mud.
* ----
* The MIT License
* Copyright (c) 2010 Andrew Tutt
* ----
*/

/* Affect Class
*
*  Affect feels like more of a struct than a class. 
*  It is mostly a container for information about what a particular affect is.
*/

class Affect {
	public $name;			// A unique string name for the affect, for ease of humans. (Like, "thief sneak" vs. "sneaky item");
	public $type;			// Type is a key, allowing us to link the affect to something (like a skill)
	public $duration;		// obvious. The units of duration are in seconds
	public $stat_modified;	// obvious. See kushtVars for the list
	public $modifier;		// And the amount.
	public $flag; 			// What is it's boolean flag? (SNEAK) for instance -- This is our Primary Key
	public $code;			// If this is a custom-coded affect (like force_sleep)
	
	// We break these apart into two arrays because of the monotonic nature of time, 
	// and the efficiency that produces
	public $affected;		// An array of affected users / items / rooms / whatever
	public $expirations;	// An array of a parallel array of expiration times
	
	function __construct() {
		$this->affected = array();
		$this->expirations = array();
	}
	
	public function run_code($object) {
		if(func_num_args()==3) { $arg1 = func_get_arg(1); $arg2 = func_get_arg(2); }
		if(func_num_args()==2) { $arg1 = func_get_arg(1); $arg2 = false; }
		if(func_num_args()==1) { $arg1 = false; $arg2 = false; }
		
		// These args could be anything
		$func = create_function('$object,$arg1,$arg2', $this->code); // remember single quotes!
		return $func($object,$arg1,$arg2); // Remember to return false if you do not wish to halt statechange execution
	}
	
	// Recursive timeout expiration
	public function expire() {
		if(!current($this->expirations)) { return; } // Nothing in Array
		
		$t = microtime(1);
		$e = current($this->expirations);
		if ($t > $e) { // First in is beyond the expire time so remove it
			$this->unaffect(current($this->affected));
			array_shift($this->affected);
			array_shift($this->expirations);
			$this->expire();
		}
	}
	
	public function affect($object) {
		$object->set($this->flag); // Set, certainly
		if(isset($this->code)) { array_push($object->coded_affects,$this); }
		
		if(func_num_args() == 2) {
			$duration = func_get_arg(1);
		} else { $duration = $this->duration; }
		
		if($duration == INFINITE) { return; }
		// Otherwise...
		array_push($this->expirations,microtime(1)+$duration);
		array_push($this->affected,$object);
	}
	
	public function unaffect($object) {
		$object->rmv($this->flag);
		if(isset($this->code)) { array_del_elem($object->coded_affects,$this); }
	}
	
	// Forced removal (disruptive)
	public function disrupt_affect($object) {
		foreach($this->affected as $k=>$c) {
			if($c==$object) {
				$this-unaffect($object);
				unset($this->affected[$k]);
				unset($this->expirations[$k]);
				return;
			}
		}
		// Infinite Duration Removed
		$this-unaffect($object);
	}
}